﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// See: https://km.glodon.com/pages/viewpage.action?pageId=311893225
#pragma once

#include <type_traits>
#include <cassert>
#include "OwnerPtr.h"

namespace gcmp
{
    /// \brief 用来在OwnerPtr<派生类>和OwnerPtr<基类>直接转换
    /// \param T 目标类型
    template<typename T>
    struct OwnerPtrDervied2BaseHelper
    {
        template<typename Derived>
        static OwnerPtr<T> from_impl(OwnerPtr<Derived>&& v, std::true_type)
        {
            //该分支必须是从派生类转为基类
            static_assert(std::is_base_of<T, Derived>::value, "std::is_base_of<T, Derived>");
            return std::move(v);
        }

        template<typename Base>
        static OwnerPtr<T> from_impl(OwnerPtr<Base>&& v, std::false_type)
        {
            //该分支必须是从基类转为派生类
            static_assert(std::is_base_of<Base, T>::value, "std::is_base_of<Base, T>");
            //TODO FIXME 理论上该场景使用static_cast即可，是否可优化?
            return OwnerPtr<T>{dynamic_cast<T*>(v.ReleaseOwnership())};
        }

        template<typename U>
        static OwnerPtr<T> from(OwnerPtr<U>&& v)
        {
            return from_impl(std::move(v), std::is_base_of<T, U>{});
        }
    };

    template<typename T>
    struct CloneableOwnerPtrEmplaceConstructTag {};

    template<typename T, class Enable = void>
    class CloneableOwnerPtr final 
    {
        static_assert(!std::is_polymorphic<T>::value, "CloneableOwnerPtr only accept polymorphic type");
    };

    /// \brief CloneableOwnerPtr类模板定义
    ///
    /// 含有OwnerPtr成员的对象的拷贝构造和赋值操作符重载的便捷使用支持
    ///
    /// 1.方便含有OwnerPtr的对象的拷贝的函数实现
    ///     a.减少拷贝构造和赋值操作符的实现代码量。
    ///     b.基本兼容OwnerPtr使用方式。
    ///
    /// 2.使用要求
    ///     a.OwnerPtr<T>类型成员变量改造方法
    ///         1）包含头文件 #include "CloneableOwnerPtr.h"
    ///         2）T需要定义并实现OwnerPtr<T> Clone() const方法；如果T有派生类D，D也要覆盖OwnerPtr<T> Clone() const
    ///         3）将OwnerPtr类型的成员，改成CloneableOwnerPtr<T>
    ///         4) 去掉T拷贝构造和赋值操作符的实现
    ///     b.因重载了==, !=和<, 如果被用到，需要实现T的EqualTo和LessThan方法。
    ///     c.使用范围：
    ///         i.在NdbObject派生体系之外使用
    ///             1.从NdbObject派生的对象不要作为T放入CloneableOwnerPtr。
    ///             2.也不要在NdbObject中，嵌入CloneableOwnerPtr成员。用DATA_WITHOUT_CHECK宏的例外，可以使用。
    ///         ii.实现为编译期阻止将POD类型的T，放入CloneableOwnerPtr，因为没有必要。
    ///         iii.其它地方可以使用，例如：SnapContext。
    ///
    /// 3.代价
    ///     a.对性能敏感、调用高频的地方，不要使用CloneableOwnerPtr。
    ///     b.MakeCloneableOwnerPtr的内存使用量和OwnerPtr相当。
    template<typename T>
    class CloneableOwnerPtr<T, typename std::enable_if<std::is_polymorphic<T>::value>::type> final
    {
        template <typename U, class Enable = void>
        friend class CloneableOwnerPtr;

        OwnerPtr<T> m_ptr{};
    public:
        CloneableOwnerPtr() = default;
        ~CloneableOwnerPtr() = default;

        template<typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
        CloneableOwnerPtr(OwnerPtr<U> v) : m_ptr{ std::move(v) } {}

        template<typename U, typename... Args>
        CloneableOwnerPtr(CloneableOwnerPtrEmplaceConstructTag<U>, Args&&... args) : m_ptr(new U(std::forward<Args>(args)...)) {}

        // 以下构造函数屏蔽掉,如果放开,容易被开发者误用
        //template<typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
        //explicit CloneableOwnerPtr(const U* u)
        //{
        //    if (!u) return;
        //    const T* v = u;
        //    m_ptr = CloneImpl(*v);
        //}

        template<typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value && !std::is_same<T, U>::value>>
        explicit CloneableOwnerPtr(CloneableOwnerPtr<U> v) : m_ptr(std::move(v.m_ptr)) {}

        CloneableOwnerPtr(const CloneableOwnerPtr& other)
        {
            auto v = other.m_ptr.get();
            if (!v) return;
            m_ptr = CloneImpl(*v);
        }

        CloneableOwnerPtr(CloneableOwnerPtr&& other) noexcept = default;

        CloneableOwnerPtr& operator = (const CloneableOwnerPtr& other)
        {
            if (std::addressof(other) != this)
            {
                if (auto v = other.m_ptr.get())
                {
                    m_ptr = CloneImpl(*v);
                }
                else
                {
                    m_ptr.reset();
                }
            }
            return *this;
        }

        CloneableOwnerPtr& operator=(std::nullptr_t ptr)
        {
            m_ptr = nullptr;
            return *this;
        }

        template<typename U,typename = std::enable_if_t<std::is_base_of<T, U>::value>>
        CloneableOwnerPtr& operator=(OwnerPtr<U>&& v)
        {
            m_ptr = std::move(v);
            return *this;
        }

        CloneableOwnerPtr& operator = (CloneableOwnerPtr&& other) noexcept = default;

        operator OwnerPtr<T>() && noexcept 
        {
            return std::move(m_ptr);
        }

        explicit operator bool() const noexcept { return m_ptr.operator bool(); }

        const T* get() const noexcept { return m_ptr.get(); }
        T* get() noexcept { return m_ptr.get();}

        const T* operator->() const
        {
            assert(*this);
            return m_ptr.get();
        }

        T* operator->()
        {
            assert(*this);
            return m_ptr.get();
        }

        const T& operator*() const
        {
            assert(*this);
            return *m_ptr;
        }

        T& operator*()
        {
            assert(*this);
            return *m_ptr;
        }

        bool operator == (std::nullptr_t other) const noexcept
        {
            return m_ptr == nullptr;
        }

        bool operator != (std::nullptr_t other) const noexcept
        {
            return m_ptr != nullptr;
        }

    private:
        template<typename U>
        static OwnerPtr<T> CloneImpl(const U& u)
        {
            return OwnerPtrDervied2BaseHelper<T>::from(u.Clone());
        }
    };

    template <class T, class U = T, class... Args>
    CloneableOwnerPtr<T> MakeCloneableOwnerPtr(Args &&...args)
    {
        static_assert(std::is_polymorphic<T>::value, "MakeCloneableOwnerPtr only accept polymorphic type");
        return CloneableOwnerPtr<T> { CloneableOwnerPtrEmplaceConstructTag<U>{}, std::forward<Args>(args)... };
    }

    // 以下为==和!=的实现,考虑到是为多态场景准备的,这里允许T,U类型不同
    // 另外需要说明的是,之所以允许和裸指针比较，是因为
    //   如果容器/算法支持 heterogeneous comparison lookup
    //   那么就只需要传递裸指针即可查询,例如存储到容器里,并使用std::find算法查找
    //   以此来避开只能OwnerPtr互相比较,或者必须使用std::find_if系列算法的问题
    template<typename T, typename U>
    bool operator == (const CloneableOwnerPtr<T>& lhs, const U* rhs)
    {
        //编译通过是需要具有T::EqualTo(const T&)的
        static_assert(std::is_base_of<T, U>::value || std::is_base_of<U, T>::value, "std::is_base_of_v<T, U> || std::is_base_of_v<U, T>");
        if (lhs && rhs)
        {
            return lhs->EqualTo(*rhs);
        }
        return (lhs.get() == rhs);
    }

    template<typename T, typename U>
    bool operator != (const CloneableOwnerPtr<T>& lhs, const U* rhs)
    {
        return !(lhs == rhs);
    }

    template<typename T, typename U>
    bool operator == (const T* lhs, const CloneableOwnerPtr<U>& rhs)
    {
        return rhs == lhs;
    }

    template<typename T, typename U>
    bool operator != (const T* lhs, const CloneableOwnerPtr<U>& rhs)
    {
        return !(rhs == lhs);
    }

    template<typename T, typename U>
    bool operator == (const CloneableOwnerPtr<T>& lhs, const CloneableOwnerPtr<U>& rhs)
    {
        return lhs == rhs.get();
    }

    template<typename T, typename U>
    bool operator != (const CloneableOwnerPtr<T>& lhs, const CloneableOwnerPtr<U>& rhs)
    {
        return !(lhs == rhs);
    }

    /// \brief 重载<
    ///
    /// 考虑到是给多态用的，这里允许T,U类型不同
    /// 可根据时机情况严格限制<的适用场景
    template<typename T, typename U>
    bool operator < (const CloneableOwnerPtr<T>& lhs, const U* rhs)
    {
        //编译通过是需要具有T::LessThan(const T&)的
        static_assert(std::is_base_of<T, U>::value || std::is_base_of<U, T>::value, "std::is_base_of_v<T, U> || std::is_base_of_v<U, T>");
        if (lhs && rhs)
        {
            return lhs->LessThan(*rhs);
        }
        return false;
    }

    template<typename T, typename U>
    bool operator < (const CloneableOwnerPtr<T>& lhs, const CloneableOwnerPtr<U>& rhs)
    {
        return lhs < rhs.get();
    }
}
